﻿// -----------------------------------------------------------------------
// <copyright file="BinaryColumn.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System.Data.Odbc;

namespace Centido.Core
{
    using System;


    /// <summary>
    ///   A binary table column.
    /// </summary>
    /// <remarks>A binary column can store byte array values.
    /// If a value is inserted using the current API then
    /// it is inserted by chunks of 4000 bytes. This process
    /// can be quite slow if using an SQL Server database.</remarks>
    /// <example>
    ///   The following example shows how to create a binary column.
    /// <code>
    ///     using System;
    ///     using Centido.Core;
    /// 
    ///     class Sample
    ///     {
    ///         static void Main()
    ///         {
    ///             var domainConfig = new DomainConfiguration()
    ///             {
    ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
    ///                 DbProviderName = "MSSQLSERVER"
    ///             };
    ///         
    ///             var domain = Domain.Build(domainConfig);
    ///         
    ///             domain.DeleteAll();
    ///             
    ///             //Creating a table
    ///             var table = domain.AddTable("my_table");
    ///             table.GrantAll();
    /// 
    ///             //Creating a binary column
    ///             var column = table.AddColumn("my_column", ColumnType.Binary)
    ///                 as BinaryColumn;
    /// 
    ///             //Inserting a binary value
    ///             var id = table.InsertRow(column.Value(new byte[]{0, 1, 2, 3}));
    /// 
    ///             Console.Write("Inserted value = ");
    /// 
    ///             foreach(var b in column.Read(id).GetBinary())
    ///                 Console.Write("{0} ", b);
    /// 
    ///             Console.WriteLine();
    ///         }
    ///     }
    /// </code>
    /// </example>
    public sealed class BinaryColumn : Column
    {
        /// <summary>
        ///   Initializes a new instance of the <see cref = "Centido.Core.BinaryColumn" /> class
        ///   for the specified column id and parent table.
        /// </summary>
        /// <param name = "columnId">The column id.</param>
        /// <param name = "table">The parent table.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        internal BinaryColumn(Guid columnId, Table table)
            : base(columnId, table)
        {
        }

        /// <summary>
        ///   Initializes a new instance of the <see cref = "Centido.Core.BinaryColumn" /> class
        ///   for the specified column id, name, display name,
        /// description, nullability, order index, customization level and parent table.
        /// </summary>
        /// <param name="columnId">The column id.</param>
        /// <param name="table">The parent table.</param>
        /// <param name="columnName">The column name.</param>
        /// <param name="displayName">The column display name.</param>
        /// <param name="description">The column description.</param>
        /// <param name="isNotNull">The column ability to hold null values.</param>
        /// <param name="orderIndex">The column order index.</param>
        /// <param name="customizationlevel">The column customization level.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        internal BinaryColumn(Guid columnId, Table table,
            string columnName, string displayName,
            string description, bool isNotNull,
            int orderIndex, int customizationlevel) : base(columnId, table,
            columnName, displayName, description, isNotNull, orderIndex, customizationlevel)
        {
        }


        /// <summary>
        ///   Gets the column type.
        /// </summary>
        public override ColumnType ColumnType
        {
            get { return ColumnType.Binary; }
        }

        /// <summary>
        ///   Gets the column value database type.
        /// </summary>
        public override OdbcType ValueOdbcType
        {
            get { return OdbcType.Image; }
        }

        /// <summary>
        ///   Gets the backend column table name.
        /// </summary>
        protected override string BackEndTableName
        {
            get { return Domain.GetObjectFullName(Db.Tables.BinaryColumnList.Name); }
        }


        /// <summary>
        ///   Adds a new binary column with the specified name to the specified table.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is a column with the same name in the same user-defined table.</exception>
        /// <returns>Returns the newly created binary table column.</returns>
        /// <example>
        ///   The following example shows how to add a binary column.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a binary table column
        ///             var column = BinaryColumn.Add(table, "my_column");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static BinaryColumn Add(Table table, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.AddColumn(columnName, ColumnType.Binary) as BinaryColumn;
        }


        /// <summary>
        ///   Adds a new binary table column with the specified id and name to the specified table.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnId">The column id.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is a column with the same id or the same name in the same user-defined table.</exception>
        /// <returns>Returns the newly created binary table column.</returns>
        /// <example>
        ///   The following example shows how to create a binary table column.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a binary table column
        ///             var column = BinaryColumn.Add(table, Guid.NewGuid(), "my_column");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static BinaryColumn Add(Table table, Guid columnId, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.AddColumn(columnId, columnName, ColumnType.Binary) as BinaryColumn;
        }


        /// <summary>
        ///   Ensures that the table contains a binary column with the specified name.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when trying to add a column and
        /// the current user has no permission to change the schema.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the 
        /// specified name but different column type.</exception>
        /// <returns>Returns a binary table column with the specified name.</returns>
        /// <example>
        ///   The following example shows how to ensure that a table has a binary column with the specified name.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a binary table column
        ///             table.AddColumn("first_column", ColumnType.Binary);
        /// 
        ///             //Ensuring the first column
        ///             BinaryColumn.Ensure(table, "first_column");
        ///             //Ensuring the second column
        ///             BinaryColumn.Ensure(table, "second_column");
        /// 
        ///             foreach(var column in table.Columns)
        ///                 Console.WriteLine("Table column: name = {0}, type = {1}", column.Name, column.ColumnType);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static BinaryColumn Ensure(Table table, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.EnsureColumn(columnName, ColumnType.Binary) as BinaryColumn;
        }


        /// <summary>
        ///   Ensures that the table contains a binary column with the specified id and the specified name.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="columnId">The column id.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when trying to add a column and
        /// the current user has no permission to change the schema.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the
        /// specified id but different column name.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the 
        /// specified id but different column type.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the specified name
        /// but different column id.</exception>
        /// <returns>Returns the table column with the specified id, the specified name and the specified type.</returns>
        /// <returns>Returns the table column with the specified id, the specified name and the specified type.</returns>
        /// <example>
        ///   The following example shows how to ensure a binary column with the specified id and
        /// the specified name.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a table column
        ///             var columnId = Guid.NewGuid();
        ///             table.AddColumn(columnId, "first_column", ColumnType.Binary);
        /// 
        ///             //Ensuring the first column
        ///             BinaryColumn.Ensure(table, columnId, "first_column");
        ///             //Ensuring the second column
        ///             BinaryColumn.Ensure(table, Guid.NewGuid(), "second_column");
        /// 
        ///             foreach(var column in table.Columns)
        ///                 Console.WriteLine("Table column: name = {0}, type = {1}", column.Name, column.ColumnType);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static BinaryColumn Ensure(Table table, Guid columnId, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.EnsureColumn(columnId, columnName, ColumnType.Binary) as BinaryColumn;
        }
    }
}